﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System;
using System.Collections.Generic;

namespace Xceed.Silverlight.Data
{
  internal sealed class GroupBufferingEnumerator : AsyncParentEnumerator<DataPath>, IPeekableEnumerator<DataPath>, ICachingEnumerator
  {
    #region Constructor

    private GroupBufferingEnumerator( GroupCacheEnumeratorBase childEnumerator, GroupHandler groupHandler )
      : base( childEnumerator )
    {
      if( groupHandler == null )
        throw new ArgumentNullException( "groupHandler" );

      m_groupHandler = groupHandler;
      m_groupHandler.ExpansionChanging += new EventHandler<ExpansionChangedEventArgs>( this.OnGroupExpansionChanging );
    }

    #endregion

    internal static GroupBufferingEnumerator Create(
      IAsyncEnumerator<DataPath> childEnumerator,
      IBufferConfigurable bufferManager,
      BufferDataHelper dataHelper,
      GroupHandler groupHandler )
    {
      BufferingEnumerator bufferEnumerator = new BufferingEnumerator( childEnumerator, bufferManager, dataHelper );
      GroupCacheEnumerator cacheEnumerator = new GroupCacheEnumerator( bufferEnumerator, dataHelper, dataHelper, dataHelper, dataHelper, 0 );

      GroupBufferingEnumerator combineEnumerator = new GroupBufferingEnumerator( cacheEnumerator, groupHandler );
      combineEnumerator.SubscribeGroupExpansionChanging( bufferEnumerator );
      combineEnumerator.SubscribeGroupExpansionChanging( cacheEnumerator );

      return combineEnumerator;
    }

    private void SubscribeGroupExpansionChanging( GroupCacheEnumeratorBase target )
    {
      if( target == null )
        return;

      m_groupExpansionChangingListeners.Add( target );
    }

    private void OnGroupExpansionChanging( object sender, ExpansionChangedEventArgs e )
    {
      foreach( var listener in m_groupExpansionChangingListeners )
      {
        listener.ExpansionChanging( e.Action, e.Path );
      }
    }

    #region IPeekableEnumerator Members

    public PeekResult<DataPath> Peek( PeekParameters parameters )
    {
      GroupCacheEnumeratorBase enumerator = ( GroupCacheEnumeratorBase )this.ChildEnumerator;

      return enumerator.Peek( parameters );
    }

    #endregion

    #region ICachingEnumerator Members

    public int CacheSize
    {
      get
      {
        ICachingEnumerator enumerator;
        if( !this.TryGetCachingEnumerator( out enumerator ) )
          return 0;

        return enumerator.CacheSize;
      }
    }

    public void SetCacheSize( int size )
    {
      ICachingEnumerator enumerator;
      if( !this.TryGetCachingEnumerator( out enumerator ) )
        return;

      enumerator.SetCacheSize( size );
    }

    public void SetCacheSize( int size, double topTrimRatio )
    {
      ICachingEnumerator enumerator;
      if( !this.TryGetCachingEnumerator( out enumerator ) )
        return;

      enumerator.SetCacheSize( size, topTrimRatio );
    }

    public void SetCacheSize( int size, SourcePosition topLimitTrim )
    {
      ICachingEnumerator enumerator;
      if( !this.TryGetCachingEnumerator( out enumerator ) )
        return;

      enumerator.SetCacheSize( size, topLimitTrim );
    }

    private bool TryGetCachingEnumerator( out ICachingEnumerator enumerator )
    {
      enumerator = this.ChildEnumerator as GroupCacheEnumerator;

      return ( enumerator != null );
    }

    #endregion

    #region IDisposable Members

    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        lock( this.SyncRoot )
        {
          m_groupHandler.ExpansionChanging -= new EventHandler<ExpansionChangedEventArgs>( this.OnGroupExpansionChanging );

          m_groupExpansionChangingListeners.Clear();
        }
      }

      base.Dispose( disposing );
    }

    #endregion

    #region Private Fields

    private readonly GroupHandler m_groupHandler;
    private readonly List<GroupCacheEnumeratorBase> m_groupExpansionChangingListeners = new List<GroupCacheEnumeratorBase>();

    #endregion
  }
}
